package xs.com.mylibrary.allinone.volley.toolbox;

import com.google.gson.Gson;

import java.lang.reflect.Type;
import java.util.HashMap;

import xs.com.mylibrary.allinone.util.LogUtils;
import xs.com.mylibrary.allinone.volley.Cache;
import xs.com.mylibrary.allinone.volley.Cache.Entry;
import xs.com.mylibrary.allinone.volley.NetworkResponse;
import xs.com.mylibrary.allinone.volley.ParseError;
import xs.com.mylibrary.allinone.volley.Request;
import xs.com.mylibrary.allinone.volley.Response;
import xs.com.mylibrary.allinone.volley.Response.ErrorListener;
import xs.com.mylibrary.allinone.volley.Response.Listener;

/**
 * Wrapper for Volley requests to facilitate parsing of json responses.
 *
 * @param <T>
 */
public class GsonRequest<T> extends Request<T> {
    /**
     * Gson parser
     */
    private final Gson mGson;
    /**
     * Callback for response delivery
     */
    private final Listener<T> mListener;
    private boolean refreshNeedCheckServer = false;
    /**
     * Class type for the response
     */
    private Type type;
    private T t;

    /**
     * @param method        Request type.. Method.GET etc
     * @param url           path for the requests
     * @param type          expected class type for the response. Used by gson for
     *                      serialization.
     * @param listener      handler for the response
     * @param errorListener handler for errors
     */
    public GsonRequest(int method, String url, Type type, Listener<T> listener,
                       ErrorListener errorListener) {

        super(method, url, errorListener);
        this.type = type;
        this.mListener = listener;
        mGson = new Gson();
    }


    @Override
    protected Response<T> parseNetworkResponse(NetworkResponse response) {
        try {
            String json = new String(response.data,
                    HttpHeaderParser.parseCharset(response.headers));
            LogUtils.d(json);
            t = mGson.fromJson(json, type);
            if (!refreshNeedCheckServer)
                saveCache(response);
            return Response.success(t,
                    HttpHeaderParser.parseCacheHeaders(response));

        } catch (Exception e) {
            if (!refreshNeedCheckServer) {
                Response<T> res = null;
                try {
                    res = getCache();
                } catch (Exception e1) {
                    e1.printStackTrace();
                    return Response.error(new ParseError(e));
                }
                if (res != null)
                    return res;
            }

            return Response.error(new ParseError(e));
        }
    }

    private Response<T> getCache() throws Exception {
        String key = "";
        try {
            key = getUrl() + getParams().hashCode();
        } catch (Exception e) {
            key = getUrl();
            e.printStackTrace();
        }
        Entry entry = Volley.diskBasedCache.get(key);

        String json = new String(entry.data, "utf-8");

        t = mGson.fromJson(json, type);

        return Response.success(t, entry);
    }

    private Entry saveCache(NetworkResponse response) {
        Cache.Entry entry = new Cache.Entry();
        entry.data = response.data;
        try {
            entry.etag = getUrl() + getParams().hashCode();
        } catch (Exception e) {
            entry.etag = getUrl();
            e.printStackTrace();
        }

        entry.softTtl = System.currentTimeMillis() + 1000 * 60 * 2;
        entry.ttl = entry.softTtl;
        entry.serverDate = System.currentTimeMillis();
        entry.responseHeaders = new HashMap<String, String>();
        Volley.diskBasedCache.put(entry.etag, entry);
        return entry;
    }

    @Override
    protected void deliverResponse(T response) {
        mListener.onResponse(response);

    }

}